<?php
/*
Auth:Sang
Desc:邮件验证类
Date:2014-11-01
*/
namespace Lib;
class VerifyEmail{
	//验证码的会话名称
	private $code_session_name = 'verify_email_code';

	//发送次数的会话名称
	private $num_session_name = 'verify_email_num';

	//1小时内最大发送次数
	private $max_send_num = 10;

	//第一次发送时间的会话名称
	private $first_session_name = 'first_send_verify_email_time';

	//最后一次发送时间的会话名称
	private $last_session_name = 'last_send_verify_email_time';

	//旧邮箱验证通过的会话名称
	private $old_checked_session_name = 'old_email_checked';

	//要验证的邮箱的会话名称
	private $verify_email_session_name = 'now_verify_email';

	//两次发送之前相隔多久 ：分钟
	private $limit_time = 1;

	// 有效期 ：小时
	private $expires = 24;

	private $error;

	/**
	* 发送邮件
	* Param $user 会员信息
	* Param $redirect_url 回调地址 即从邮件中点击的地址 系统会在该地址后面加上验证
	*/
	public function send($user,$redirect_url){
		if(empty($user['email']) || !is_mail($user['email'])){
			$this->error = "不是有效的邮箱地址";
			return false;
		} 
		if(empty($redirect_url) || !is_url($redirect_url)){
			$this->error = "不是有效的URL";
			return false;
		}
		$this->setVerifyEmail($user['email']);
		//发送次数
		$send_num = $this->getSendNum();
		//检查在规定时间内，发送次数是否超出限制
		if($this->checkSendNum($send_num)!=true){
			$this->error = '对不起，您的发送次数太频繁，请休息一下';
			return false;
		}
		//生成验证码
		$verify_code = $this->genVerifyCode();
		//写入session
		$this->setVerifyCode($verify_code);
		// 邮件标题
		$subject = config('site_name').'验证邮件';
		//邮件主题
		$body = $this->getBody($user,$redirect_url);
		if(empty($body)){
			return false;
		}
		$ret = send_mail($user['email'],$subject,$body);
		if($ret===true){
			//记录第一次发送时间
			if($send_num==0){
				session($this->first_session_name,time());
			}
			//记录发送次数
			$this->setSendNum();
			//记录最后发送时间
			$this->setLastTime();
			return true;
		}
		$this->error = $ret;
		return false;
	}

	private function getSendNum(){
		return intval(session($this->num_session_name));
	}

	private function setSendNum(){
		return session($this->num_session_name,$this->getSendNum()+1);
	}

	private function setLastTime(){
		return session($this->last_session_name,time());
	}

	private function getLastTime(){
		return session($this->last_session_name);
	}

	private function setVerifyCode($code){
		return session($this->code_session_name,$code,$this->expires*3600);
	}

	private function setFirstTime(){
		return session($this->first_session_name,time());
	}

	private function getFirstTime(){
		return session($this->first_session_name);
	}

	private function getVerifyCode(){
		return session($this->code_session_name);
	}

	public function setVerifyEmail($email){
		return session($this->verify_email_session_name,$email);
	}

	public function getVerifyEmail(){
		return session($this->verify_email_session_name);
	}

	private function checkSendNum($send_num){
		//最后发送时间
		$last_send_time = $this->getLastTime();
		if(!empty($last_send_time) && time()-$last_send_time<$this->limit_time*60){
			return false;
		}
		//第一次发送时间
		$first_send_time = $this->getFirstTime();
		if(!empty($first_send_time) && time()-$first_send_time<24*3600 && $send_num>=$this->max_send_num){
			return false;
		}
		return true;
	}

	private function genVerifyCode(){
		return md5(uniqid($_SERVER['REMOTE_ADDR']).rand(1111111,9999999));
	}

	private function createUrl($url){
		$code = $this->getVerifyCode();
		if(strpos($url,'?')!==false){
			$url .= '&code='.$code;
		}else{
			$url .= '?code='.$code;
		}
		return $url;
	}

	private function getBody($user,$redirect_url){
		//在数据库中ID为1的模板
		$tpl = model('MailTpl')->getMailTplById(1);
		if(empty($tpl) || empty($tpl['content'])){
			$this->error = '不存在邮件模板';
			return false;
		}
		//生成链接
		$url = $this->createUrl($redirect_url);
		$patten = ['{$user_name}','{$site_name}','{$verify_url}','{$expires}','{$date}'];
		$replace = [$user['user_name'],config('site_name'),$url,$this->expires,date('Y-m-d H:i:s')];
		return str_replace($patten,$replace,htmlspecialchars_decode($tpl['content']));
	}

	public function verifyCode(){
		$code = get('code','','trim');
		$session_code = $this->getVerifyCode();
		$ret = !empty($session_code) && !empty($code) && $code == $session_code;
		if($ret!==false){
			return true;
		}else{
			$this->clearSession();
			return false;
		}
		return false;
	}

	public function getError(){
		return $this->error;
	}

	public function setOldStatus($status=true){
		session($this->old_checked_session_name,$status);
	}

	public function getOldStatus(){
		return !empty(session($this->old_checked_session_name));
	}

	public function clearSession(){
		session($this->code_session_name,null);
		session($this->num_session_name,null);
		session($this->first_session_name,null);
		session($this->last_session_name,null);
		session($this->old_checked_session_name,null);
		session($this->verify_email_session_name,null);
	}
}